#include "executor.h"
#include "database.h"
#include "error.h"
#include "event.h"
#include "event_mapping.h"
#include <critical.h>
#include <memory.h>

static exeinfo exe;
static critical cs;

void executor_init()
{
    init_critical( &cs );
    enter_critical( &cs );
    exe.task[0] = lt_create();
    exe.task[1] = lt_create();
    exe.task[2] = lt_create();
    exe.task[3] = lt_create();
    memset( exe.thread, 0, sizeof(exe.thread) );
    memset( exe.thread_event, 0, sizeof(exe.thread_event) );
    leave_critical( &cs );
}

void executor_uninit()
{
    int i;
    enter_critical( &cs );

    for( i = 0; i < MAX_THREAD; ++i )
    {
        if( exe.thread[i] == NULL )
            break;
        exe.thread_event[i] = THREAD_STOP;
    }
    lt_destroy( exe.task[0] );
    lt_destroy( exe.task[1] );
    lt_destroy( exe.task[2] );
    lt_destroy( exe.task[3] );

    leave_critical( &cs );
    destroy_critical( &cs );
}

int push_task( void *task, int priority )
{
    if( priority < 0 || priority > 1 )
        return ERR_PARAMETER;
    enter_critical( &cs );
    lt_pushb( exe.task[priority+2], task );
    leave_critical( &cs );
    return 0;
}

int push_task_sys( void *task, int priority )
{
    if( priority < 0 || priority > 1 )
        return ERR_PARAMETER;
    enter_critical( &cs );
    lt_pushb( exe.task[priority], task );
    leave_critical( &cs );
    return 0;
}

void* pop_task()
{
    int i;
    void *val = NULL;
    enter_critical( &cs );
    for( i = 0; i < 4; ++i )
    {
        if( lt_size( exe.task[i] ) > 0 )
        {
            val = lt_popf( exe.task[i] );
            break;
        }
    }
    leave_critical( &cs );
    return val;
}

int set_thread_count( int count )
{
    int i;
    enter_critical( &cs );

    for( i = 0; i < count; ++i )
    {
        if( exe.thread[i] == 0 )
        {
            exe.thread_event[i] = THREAD_RUN;
            exe.thread[i] = CreateThread( NULL, 0, thread_func, exe.thread_event+i, 0, NULL );
        }
    }
    for( ; i < MAX_THREAD; ++i )
    {
        if( exe.thread[i] != 0 )
        {
            exe.thread_event[i] = THREAD_STOP;
            exe.thread[i] = 0;
        }
    }
    
    leave_critical( &cs );
    return 0;
}

DWORD WINAPI thread_func( void* para )
{
    int i = 0;
    event *task;
    event_map *em;
    int *status = (int*)para;
    while( *status == THREAD_RUN )
    {
        task = (event*)pop_task();
        if( task != NULL )
        {
            update_current_event( task );
            em = get_processor( task->id );
            if( em != NULL && em->func != NULL )
            {
                process( em->func, task );
            }
            event_destroy( task );
        }
        else
        {
            Sleep(1);
        }
    }
    return 0;
}
